package abacab.utils;

/**
 * Represents a queue of actors.<br />
 * This implementation is not thread safe
 * 
 * @param <T>
 *          the type of added objects
 */
public class SimpleLinkedQueue<T> {
	/** The head */
	private Item<T>	head;

	/** The tail */
	private Item<T>	tail;

	/**
	 * Create an instance
	 */
	public SimpleLinkedQueue() {
		// nothing to do
	}

	/**
	 * Indicates if the queue is empty.
	 * 
	 * @return true if the queue is empty
	 */
	public final boolean isEmpty() {
		return this.tail == null;
	}

	/**
	 * Get the number of queued items.<br />
	 * Complexity: O(n).
	 * 
	 * @return the number of queued items
	 */
	public final int size() {
		int count = 0;
		for (Item<T> e = this.head; e != null; e = e.next) {
			count++;
		}
		return count;
	}

	/**
	 * Add an object to the queue
	 * 
	 * @param object
	 *          the object
	 */
	public void offer(T object) {
		Item<T> item = new Item<T>(object);
		if (this.tail == null) {
			this.head = this.tail = item;
		}
		else {
			this.tail.next = item;
			this.tail = item;
		}
	}

	/**
	 * Get the first object in the queue.
	 * 
	 * @return the first object in the queue
	 */
	public T poll() {
		if (this.head != null) {
			T object = this.head.object;
			this.head = this.head.next;
			if (this.head == null) {
				this.tail = null;
			}
			return object;
		}
		return null;
	}

	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	// ************************************************************************
	// ************************************************************************
	// AN ITEM IN THE QUEUE
	// ************************************************************************
	// ************************************************************************

	/**
	 * An item in the priority queue
	 * 
	 * @param <T>
	 *          the type of object
	 */
	private static final class Item<T> {
		/** The object */
		final T	object;

		/** The next item */
		Item<T>	next;

		/**
		 * Create a queued item
		 * 
		 * @param object
		 *          the object
		 */
		Item(T object) {
			this.object = object;
		}
	}
}